/**
 * calculator
 *
 * @author : tzy
 * @Date : 2021-03-17
 * @Description:
 **/

package com.tang.calculator.symbols;

import com.tang.calculator.Calculator;
import com.tang.calculator.config.Formula;
import com.tang.calculator.context.CalculateContext;
import com.tang.calculator.utils.NumFormatFactory;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationContext;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Data
@Slf4j
public class ReferenceValueSymbol extends AbstractReferenceValueSymbol{

    CalculateContext context;
    private Calculator calculator;
    private ApplicationContext applicationContext;
    public ReferenceValueSymbol(ApplicationContext applicationContext, String name) {
        super(name);
        this.applicationContext = applicationContext;
        this.calculator = (Calculator) applicationContext.getAutowireCapableBeanFactory().getBean("defaultCalculator");
    }

    @Override
    public BigDecimal getValue() {
        Object obj = context.getObj();
        String name = getName();
        if (!StringUtils.isEmpty(name)) {
            String[] split = name.split("\\.");
            try {
                Formula formula = context.getFormulaVO();
                formulaValidity(formula);
                String result = formula.getResult();
                String clazz = split[0];
                String field = split[1];
                if (result != null) {
                    String[] resultSplit = result.split("\\.");
                    //如果和返回结果相同类型
                    if (clazz.equals(resultSplit[0])) {
                        BigDecimal bigDecimal = NumFormatFactory.format(obj, field);
                        return bigDecimal.setScale(ValueSymbolHelper.getPrecision());
                    } else {
                        //根据filters从resource中找到对应数据
                        BigDecimal bigDecimal = dataMining(clazz, field, obj);
                        return bigDecimal.setScale(ValueSymbolHelper.getPrecision());
                    }
                } else {
                    BigDecimal bigDecimal = dataMining(clazz, field, obj);
                    return bigDecimal.setScale(ValueSymbolHelper.getPrecision());
                }
            } catch (Exception e) {
                log.error(e.getMessage());
                throw new RuntimeException(e.getMessage());
            }
        } else {
            return new BigDecimal(0).setScale(ValueSymbolHelper.getPrecision());
        }
    }

    public Object getData() {
        String name = getName();
        return context.getResource().get(name);
    }

    private BigDecimal dataMining(String clazz, String field, Object obj) throws Exception {
        Map<String, Object> rootResource = context.getResource();
        Object data = rootResource.get(clazz);
        Object rs;
        if (data instanceof List) {
            rs = fromList(clazz, field, data, obj);
        }else if (data instanceof Map) {
            Map map = (Map) data;
            rs = map.get(field);
        }else {
            rs = NumFormatFactory.format(data, field);
        }

        if (rs instanceof String) {
            return new BigDecimal(rs.hashCode());
        } else {
            return (BigDecimal) rs;
        }
    }

    private Object fromList(String clazz, String field, Object data, Object obj) throws Exception {
        List list = (List) data;
        String filter = findFilter(clazz);
        Object rs = null;
        for (Object o : list) {
            Formula formula = new Formula();
            formula.setFormula(filter);
            CalculateContext context = new CalculateContext(formula);
            Map<String, Object> resource = new HashMap<>();
            resource.put(clazz, o);
            resource.put(obj.getClass().getSimpleName(), obj);
            context.setResource(resource);
            BigDecimal filterOut = calculator.execute(context);
            if (filterOut.compareTo(new BigDecimal(1)) == 0) {
                Field value = o.getClass().getDeclaredField(field);
                value.setAccessible(true);
                rs = value.get(o);
                break;
            } else {

            }
        }
        return rs;
    }

    private String findFilter(String clazz) {
        List<String> filters = context.getFormulaVO().getFilters();
        if (CollectionUtils.isEmpty(filters)) throw new RuntimeException("没有过滤器可使用");
        String filter = null;
        for (String f : filters) {
            String[] fArr = f.split(":");
            String s = fArr[0];
            if (clazz.equals(s)) filter = fArr[1];
        }
        return filter;
    }

    private void formulaValidity(Formula formula) {
        if (formula == null) throw new RuntimeException("找不到公式对象");
    }

}
